//
// Created by wangjunjun on 2024/3/21.
//

#include "monitor.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <algorithm>
#include <cstring>
#include <dirent.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include "../log/log.h"
constexpr int Max_Reties = 6; // 最大的连接次数
CMonitor::CMonitor():m_serverAddress(""),
                     m_directoryPath(""),
                     m_ftpPort(2121){  //ftp端口

}
CMonitor::~CMonitor(){

}

void CMonitor::attach(Observer* observer){
    std::lock_guard<std::mutex> lock(m_mtx);
    observers.push_back(observer);
}
void CMonitor::detach(Observer* observer){
    std::lock_guard<std::mutex> lock(m_mtx);
    auto it = std::find(observers.begin(), observers.end(), observer);
    if (it != observers.end()) {
        observers.erase(it);
    }
}
void CMonitor::notify(bool isOnline, bool hasFiles){
    std::lock_guard<std::mutex> lock(m_mtx);
    for (Observer* observer : observers) {
        observer->update(isOnline, hasFiles);
    }
}
void CMonitor::startMonitoring(const std::string& serverAddress, const int  serverPort, const std::string& directoryPath){
    m_directoryPath = directoryPath;
    m_serverAddress = serverAddress;
    m_ftpPort = serverPort;
    m_stop = false;

    monitorThread = std::thread(&CMonitor::monitorDirectory, this);
}
void CMonitor::stopMonitoring(){
    m_stop = true;
    monitorThread.join();
}
void CMonitor::monitorDirectory(){
    while (!m_stop) {
        bool hasFiles = checkDirectoryFilesRecursive(m_directoryPath);
        bool isOnline = checkServerStatus();
        notify(isOnline, hasFiles);
        std::this_thread::sleep_for(std::chrono::seconds(30));
    }
}
bool CMonitor::checkDirectoryFilesRecursive(const std::string& path){
    LOG_INFO("path:{}", path.c_str());
    DIR* dir = opendir(path.c_str());
    if (dir == nullptr) {
        LOG_ERROR("Failed to open directory: {}", path);
        return false;
    }

    bool hasFiles = false;
    struct dirent* entry;
    while ((entry = readdir(dir)) != nullptr) {
        if (entry->d_type == DT_REG) {
            LOG_INFO("Directory has files." );
            hasFiles = true;
            break;
        } else if (entry->d_type == DT_DIR) {
            if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
                std::string subDirPath = path + "/" + entry->d_name;
                hasFiles = checkDirectoryFilesRecursive(subDirPath);
                if (hasFiles) {
                    break;
                }
            }
        }
    }

    closedir(dir);
    return hasFiles;
}
bool CMonitor::checkServerStatus() {
 for (int tmpCount = 0; tmpCount <= Max_Reties; ++tmpCount) {
        // 创建套接字
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock == -1) {
            LOG_ERROR("Failed to create socket");
            std::this_thread::sleep_for(std::chrono::seconds(3)); // 等待1秒再重试
            continue;
        }

        // 设置服务器地址和端口
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_port = htons(m_ftpPort);
        if (inet_pton(AF_INET, m_serverAddress.c_str(), &(server.sin_addr)) <= 0) {
            LOG_ERROR("Invalid address/Address not supported");
            close(sock);
            std::this_thread::sleep_for(std::chrono::seconds(3)); // 等待1秒再重试
            continue;
        }

        // 连接服务器
        if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0) {
            // 关闭套接字
            close(sock);
            return true;
        } else {
            LOG_INFO("Failed to connect to the server, retrying...");
            close(sock);
            std::this_thread::sleep_for(std::chrono::seconds(3)); // 等待1秒再重试
        }
    }
    LOG_INFO("Connection attempts exceeded the limit");
    return false;
}

void  CMonitorStatus::update(bool isOnline, bool hasFiles) {
    if (isOnline && hasFiles) {
        m_MonitorStatus = true;
    } else {
        m_MonitorStatus = false;
        //判斷是否存在空目錄
        LOG_INFO("isOnline {} ", isOnline);
        LOG_INFO("hasFiles {}", hasFiles);
    }
};
bool  CMonitorStatus::GetMonitorStatue() const{
    return m_MonitorStatus;
}